package com.jetpackframework.virtualapk;


import android.app.Activity;
import android.app.Application;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

import androidx.annotation.NonNull;

import com.jetpackframework.ContextUtil;
import com.jetpackframework.Reflector;
import com.jetpackframework.virtual.PluginContext;
import com.jetpackframework.virtual.VirtualApk;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;

/**
 * 加载启动插件Apk中的Activity
 */
public class VirtualInstrumentation extends Instrumentation implements Handler.Callback {
    private final Application application;
    private final Instrumentation instrumentation;
    private VirtualApk apk;

    private static final int LAUNCH_ACTIVITY = 100;
    private static final int EXECUTE_TRANSACTION = 159;

    public VirtualInstrumentation(Application application, Instrumentation instrumentation) {
        this.application = application;
        this.instrumentation = instrumentation;
    }
    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        injectIntent(intent);
        try {
            return Reflector.with(instrumentation).method("execStartActivity",Context.class,IBinder.class,IBinder.class,Activity.class,Intent.class,int.class,Bundle.class)
                    .call(who,contextThread,token,target,intent,requestCode,options);
        } catch (Reflector.ReflectedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, String target,
            Intent intent, int requestCode, Bundle options) {
        injectIntent(intent);
        try {
            return Reflector.with(instrumentation).method("execStartActivity",Context.class,IBinder.class,IBinder.class,String.class,Intent.class,int.class,Bundle.class)
                    .call(who,contextThread,token,target,intent,requestCode,options);
        } catch (Reflector.ReflectedException e) {
            e.printStackTrace();
        }
        return null;
    }
    private void injectIntent(Intent intent) {
        ComponentName component = intent.getComponent();
        Log.e("TAG-----","component="+component);
        if (component == null || component.getPackageName().equals(application.getPackageName())){
            return;
        }
        String targetClassName = component.getClassName();
        String packageName = component.getPackageName();
        Set<String> categories = intent.getCategories();
        if (categories != null && !categories.isEmpty()){
            intent.putExtra(Contracts.VIR_CATE,new ArrayList<>(categories));
            categories.clear();
        }
        intent.addCategory(Contracts.VIR_CLASSNAME+targetClassName);
        intent.addCategory(Contracts.VIR_PACKAGENAME+packageName);

        ActivityInfo activityInfo = VirtualInstaller.getInstance().getVirtualApk(packageName).getActivityInfo(component);
        String stubActivity = getStubActivity(activityInfo);
        intent.setClassName(application,stubActivity);
    }

    private String getStubActivity(ActivityInfo activityInfo) {
        String string = "com.virtual.%s.%s.v$%d";
        String launchMode = "standard";
        String screenOrientation = "portrait";
        switch (activityInfo.launchMode){
            case ActivityInfo.LAUNCH_SINGLE_TASK:
                launchMode = "singleTask";
                break;
            case ActivityInfo.LAUNCH_SINGLE_TOP:
                launchMode = "singleTop";
                break;
            case ActivityInfo.LAUNCH_MULTIPLE:
                launchMode = "standard";
                break;
            case ActivityInfo.LAUNCH_SINGLE_INSTANCE:
                launchMode = "singleInstance";
                break;
        }
        switch (activityInfo.screenOrientation){
            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
                screenOrientation = "landscape";
                break;
            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
                screenOrientation = "portrait";
                break;
        }
        string = String.format(Locale.CHINA,string,launchMode,screenOrientation,activityInfo.launchMode);
        return string;
    }

    @Override
    public Activity newActivity(ClassLoader cl, String className, Intent intent) throws IllegalAccessException, InstantiationException {
        try {
            return (Activity) cl.loadClass(className).newInstance();
        }catch (ClassNotFoundException e){
            return newActivity(intent);
        }
    }

    private Activity newActivity(Intent intent) {
        Set<String> categories = intent.getCategories();
        String className = null;
        String packageName = null;
        for (String category : categories){
            if (category.startsWith(Contracts.VIR_CLASSNAME)){
                className = category.substring(Contracts.VIR_CLASSNAME.length());
            }
            if (category.startsWith(Contracts.VIR_PACKAGENAME)){
                packageName = category.substring(Contracts.VIR_PACKAGENAME.length());
            }
        }
        try {
            apk = VirtualManager.getInstance().getVirtualApk(packageName);
            ClassLoader classLoader = apk.getClassLoader();
            Activity activity = (Activity) classLoader.loadClass(className).newInstance();
            activity.setIntent(intent);
            Reflector.QuietReflector.with(activity).field("mResources").set(apk.getResources());
            return activity;
        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Application newApplication(ClassLoader cl, String className, Context context) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        return instrumentation.newApplication(cl, className, context);
    }

    @Override
    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        //更换插件中的Context
        try {
            if (apk != null){
                Reflector.with(activity).field("mBase").set(new PluginContext(apk,ContextUtil.get()));
                Reflector.with(activity).field("mApplication").set(apk.getApplication());
            }
            instrumentation.callActivityOnCreate(activity,icicle);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean handleMessage(@NonNull Message msg) {
        if (msg.what == LAUNCH_ACTIVITY){   //android 9.0之前处理Activity的主题0
            Object activityClientRecord = msg.obj;
            try {
                Intent intent = Reflector.with(activityClientRecord).field("intent").get();
                ActivityInfo activityInfo = Reflector.with(activityClientRecord).field("activityInfo").get();
                VirtualApk virtualApk = VirtualManager.getInstance().getVirtualApk(intent.getComponent().getPackageName());
                if (virtualApk != null){
                    int theme = virtualApk.getThemeByComponent(intent.getComponent());
                    if (theme != 0){
                        activityInfo.theme = theme;
                    }
                }
            } catch (Reflector.ReflectedException e) {
                e.printStackTrace();
            }
        }else if (msg.what == EXECUTE_TRANSACTION){  //android 9.0之后处理Activity的主题
            Object clientTransaction = msg.obj;
            try {
                List<?> mActivityCallbacks = Reflector.with(clientTransaction).field("mActivityCallbacks").get();
                for (Object mCallback : mActivityCallbacks){
                    if (!mCallback.getClass().getSimpleName().equals("LaunchActivityItem"))
                        return false;
                    Intent intent = Reflector.with(mCallback).field("mIntent").get();
                    ActivityInfo activityInfo = Reflector.with(mCallback).field("mInfo").get();
                    VirtualApk virtualApk = VirtualManager.getInstance().getVirtualApk(intent.getComponent().getPackageName());
                    if (virtualApk != null){
                        int theme = virtualApk.getThemeByComponent(intent.getComponent());
                        if (theme != 0){
                            activityInfo.theme = theme;
                        }
                    }
                }
            } catch (Reflector.ReflectedException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}

